package com.example.demo.service.serviceImpl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.mapper.ClickHouse.ClickHouseMapper;
import com.example.demo.mapper.*;
import com.example.demo.pojo.Accounts.FundAccounts;
import com.example.demo.pojo.Accounts.TotalAmount;
import com.example.demo.pojo.Competitions.Competitions;
import com.example.demo.pojo.Order.CreatOrderPojo;
import com.example.demo.pojo.Order.Orders;
import com.example.demo.pojo.Order.PutOrders;
import com.example.demo.pojo.R;
import com.example.demo.pojo.Stock.Stock;
import com.example.demo.pojo.Stock.StockPositions;
import com.example.demo.service.OrderService;
import com.example.demo.utils.*;
import com.example.demo.utils.TokenUtil.decryptToken;
import com.example.demo.utils.TokenUtil.spiltUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static com.example.demo.utils.ConstantUtils.*;
import static com.example.demo.utils.OrderConstants.UNFILLED;


@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Orders> implements OrderService {
    @Resource
    private OrderMapper orderMapper;

    @Resource
    private PutOrderMapper putOrderMapper;
    @Resource
    private FundAccountMapper fundAccountMapper;

    @Resource
    private FundAccountUtils fundAccountUtils;

    @Resource
    private StockPositionsMapper stockPositionsMapper;
    @Resource
    private StockPositionsUtils stockPositionsUtils;
    @Resource
    private KafkaSenderUtils kafkaSenderUtils;

    @Resource
    private OrderUtils orderUtils;


    @Resource
    private StockUtils stockUtils;

    @Resource
    private StockUtilsNew stockUtilsNew;

    @Resource
    private PutOrderUtils putOrderUtils;

    @Resource
    private UserUtil userUtil;

    @Resource
    private CompetitionMapper competitionMapper;

    @Resource
    private ClickHouseMapper clickHouseMapper;

    @Resource
    private TotalAmountMapper totalAmountMapper;

    @Resource
    private UserFundAccountMapper userFundAccountMapper;


    @Override
    @Transactional
    public R<T> creatOrderNew(String token, CreatOrderPojo creatOrderPojo) {
        //获取当前用户的id
        String decrypt = decryptToken.decrypt(token);
        String userName = spiltUtils.getUserName(decrypt);
        Integer userId = userUtil.getUserId(userName);
        //判断是否实名
        boolean realNameAuthentication = userUtil.getRealNameAuthentication(userId);
        if (!realNameAuthentication) {
            return R.failed("你还未进行实名认证！");
        }

        // 前置判断
        String stockCode = creatOrderPojo.getStockCode();
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        //测试代码，将时间改为2024-03-12 00:00:00
        String test = "2024-03-12 00:00:00";
//        LocalDateTime localDateTime = LocalDateTime.now();
        LocalDateTime localDateTime = LocalDateTime.parse(test,df);
        Stock stock = clickHouseMapper.getStockInfo(stockCode,localDateTime);

        if (stock == null){
            log.info("该股票不存在！");
            return R.failed("该股票不存在！");
        }

        //判断今天是否为交易日
        if (!stockUtilsNew.isTradingDay(localDateTime.format(df))) {
            return R.failed("今天不是交易日!");
        }

        //判断该股票是否已经停牌
        if(stock.getStopReason() == 1){
            return R.failed("该股票已停牌，无法交易！");
        }

        //判断挂单价格是否超过当天这只股票的涨停价或者低于其跌停价,如果是的话需要重新挂单
        BigDecimal upPrice = stock.getMaxUp();
        BigDecimal downPrice = stock.getMaxDown();
        if (stock.getLast().compareTo(upPrice) > 0) {
            return R.failed("您当前挂单价格超过当天股票的涨停价了哦!请重新挂单!");
        }
        if (stock.getLast().compareTo(downPrice) < 0) {
            return R.failed("您当前挂单价格低于当天股票的跌停价了哦!请重新挂单!");
        }

        //判断是买入还是卖出,分四种情况,即时买入,即时卖出,限价买入,限价卖出
        //获取订单类型，即时买入,1 限价买入,2 即时卖出,3 限价卖出,4 ,不是这四种交易类型，返回-1
//        Integer orderType = stockPositionsUtils.getOrderType(creatOrderPojo);
        if(creatOrderPojo.getOrderType().equals(-1)){
            log.info("输入的交易类型有误，需重新输入！");
            return R.failed("您输入的交易类型有误，请重新输入！");
        }
        //如果是买入的话，是否为即时买入，如果是，挂单价小于最新价则返回
        if(creatOrderPojo.getOrderType().equals(1) && (creatOrderPojo.getPrice().compareTo(stock.getLast()) < 0)){
            return R.failed("当前即时买入价格小于最新价！请重新操作！");
        }
        //如果是买入的话，是否为即时买入，如果是，挂单价小于最新价则返回并且买入价格大于涨停价则返回
        if(creatOrderPojo.getOrderType().equals(1) && (creatOrderPojo.getPrice().compareTo(stock.getMaxUp()) > 0)){
            return R.failed("当前即时买入价格大于当天此股票涨停价！请重新操作！");
        }
        //如果是卖出的话，是否为即时卖出，如果是，挂单价大于最新价则返回
        if(creatOrderPojo.getOrderType().equals(3) && (creatOrderPojo.getPrice().compareTo(stock.getMaxDown()) < 0)){
            return R.failed("当前即时卖出价格小于当天此股票跌停价！请重新操作！");
        }

        // 将最新价放入creatOrderPojo中
        creatOrderPojo.setLast(stock.getLast());

        return buyAndSellStock(userId,creatOrderPojo,stock);
    }

    /* 买入卖出核心逻辑
    三张核心表
    FundAccounts 用户资金账户表
    Orders 订单表
    StockPositions 股票持仓表（单个用户在此比赛中的单只个股）

    注意！！ 某支股票现价100元，我是可以以110元的价格买进去的，亦可以以90的价格卖出去，那么StockPositions表中的相关字段都要更新

    买入：
    前置条件判断完后，创建新的order表，
    使用userid和competitionid作为索引，更新FundAccounts 用户资金账户表中的available_fund可用资金字段，frozen_fund冻结资金字段。
    如果是第一次买入这只股票，则创建StockPositions 股票持仓表，判断查询返回的结果为不为null，如果为null则创建新的StockPositions，接下来一样进行相应字段的更新
    如果为即时买入，则进行持有数量，冻结数量，持仓市值，持仓盈利，成本价，市值，盈亏比例，持仓比例的计算，并更新最新价，
    其中，最新价在这里直接拿即可，如果为限价买入则无需计算，将订单送进flink里面
    等待最新价小于等于限价时，即order表中的price小于等于last的时候才进行交易，并更新StockPositions和FundAccounts表

    卖出：
    前置条件判断完后，创建新的order表，
    使用userid和competitionid作为索引，更新FundAccounts 用户资金账户表中的available_fund可用资金字段
    更新StockPositions表
    如果为即时卖出，
    如果卖出数量等于持有数量，则删除StockPositions表，这里注意，删除这张表，对FundAccounts表中的total_asset总资产，available_fund可用资金，frozen_fund冻结资金进行更新
    （这里注意，刚从这只股票撤下来的资金无法再次购买此股票，只能去买别的股票，但是为了简单起见，统一把这部分资金划进frozen_fund冻结资金中）
    更新position_value持仓市值，amout成本价总金额，以及持仓总盈亏。
    则进行持有数量，冻结数量，持仓市值，持仓盈利，成本价，市值，盈亏比例，持仓比例的计算，并更新最新价，其中，最新价在这里直接拿即可，如果为限价卖出则无需计算，将订单送进flink里面
    等待最新价大于等于限价时，即order表中的price大于等于last的时候才进行交易，并更新StockPositions和FundAccounts表
      买入和卖出时，即时和限价所需要操作的字段有所不同：

    以下限价没有更新的字段将会在flink中进行更新
    FundAccounts，更新
    即时买入时更新：
    available_fund 可用资金， position_value持仓市值 ，amount 总成本价 position_profit_loss 持仓总盈亏， total_asset 总资产
    限价买入时更新：
    available_fund 可用资金  ,frozen_fund 冻结资金
    即时卖出时更新：
    available_fund 可用资金， position_value持仓市值 ，amount 总成本价 position_profit_loss 持仓总盈亏， total_asset 总资产
    限价卖出时无需更新此表

    StockPositions，更新
    即时买入时更新：
    quantity 持有数量 ，frozen_quantity 冻结数量，position_value 持仓市值,
    position_profit_loss 持仓盈亏，cost_price 成本价，latest_price 最新价，
    profit_loss_ratio 盈亏比例，position_ratio 持仓比例
    限价买入时，无需更新StockPositions表
    即时卖出时更新：
    quantity 持有数量 ，available_quantity 可用数量，frozen_quantity 冻结数量，position_value 持仓市值,
    position_profit_loss 持仓盈亏，cost_price 成本价，latest_price 最新价，
    profit_loss_ratio 盈亏比例，position_ratio 持仓比例
    限价卖出时更新：
    available_quantity 可用数量，frozen_quantity 冻结数量

   */

    private R<T> buyAndSellStock(Integer userId,CreatOrderPojo creatOrderPojo,Stock stock){
        Orders orders = new Orders();
        //分买入卖出
        //获取订单类型，即时买入,1 限价买入,2 即时卖出,3 限价卖出,4
//        Integer orderType = stockPositionsUtils.getOrderType(creatOrderPojo);
        String orderType =stockPositionsUtils.setOrdersOrderType(creatOrderPojo.getOrderType());
        //买入,即时买入和限价买入的逻辑一样
        if(BUY.equals(orderType.substring(2))) {
            //查询持仓信息
            StockPositions positions = stockPositionsUtils.getStockPositionsNew(userId,creatOrderPojo.getCompetitionid(),creatOrderPojo.getStockCode());
            //如果有持仓则更新stockPositions持仓表，以及fundAccount表
            if (positions != null) {
                // 先更新fundAccount表
                boolean update = fundAccountUtils.updateFundAccountsForBuyTransactionNew(creatOrderPojo,userId,creatOrderPojo.getOrderType());
                if (update) {
                    // fundAccount表更新成功，则新建orders表
                    orders.setOrderId(creatOrderPojo.getCompetitionid());//绑定比赛id(这里的意思是通过比赛id来生成orderid)
                    orders.setUserId(userId);
                    orders.setCompetitionId(creatOrderPojo.getCompetitionid());//绑定比赛id
                    orders.setOrderType(stockPositionsUtils.setOrdersOrderType(creatOrderPojo.getOrderType()));
                    orders.setBuyMethod(orders.getOrderType().substring(2));
                    orders.setStockCode(creatOrderPojo.getStockCode());
                    orders.setStockName(creatOrderPojo.getStockName());
                    orders.setPrice(creatOrderPojo.getPrice());
                    orders.setOrderQuantity(creatOrderPojo.getQuantity());
                    orders.setTime(new Date());
                    // 如果为即时买入则说明订单已完成
                    if(creatOrderPojo.getOrderType().equals(1)){
                        orders.setFinishQuantity(creatOrderPojo.getQuantity());
                        orders.setDrawQuantity(0);
                        orders.setOrderStatus("已成交");
                    }
                    else {
                        orders.setFinishQuantity(0);
                        orders.setDrawQuantity(0);
                        orders.setOrderStatus("未成交");
                        // 添加订单信息
                        String orderMessage = orderUtils.createOrderMessageNew(orders, UNFILLED);
                        // 发送订单消息
                        kafkaSenderUtils.sendOrderMessage("market-order-submissions", orderMessage);
                        int insert = orderMapper.insert(orders);
                        return R.success("委托操作成功");
                    }

                    int insert = orderMapper.insert(orders);
                    if (insert > 0) {
                        // 上面两张表都更新成功，并且为即时买入，则最后更新StockPositions表
                        boolean stockPositionsUpdate = stockPositionsUtils
                                .updateStockPositionsAfterBuyTransactionNew(creatOrderPojo, userId, creatOrderPojo.getOrderType());
                        if (stockPositionsUpdate) {
                            return R.success("交易成功！");
                        }
                        return R.failed("交易失败！");
                        //  如果为限价买入则直接返回交易成功
                    }
                    return R.failed("交易失败！");
                }
            }
            //如果没有持仓则新建持仓表
            else {
                // 先更新fundAccount表
                boolean update = fundAccountUtils.updateFundAccountsForBuyTransactionNew(creatOrderPojo, userId,creatOrderPojo.getOrderType());
                if (update) {
                    // fundAccount表更新成功，则新建orders表
                    orders.setOrderId(creatOrderPojo.getCompetitionid());//绑定比赛id(这里的意思是通过比赛id来生成orderid)
                    orders.setUserId(userId);
                    orders.setCompetitionId(creatOrderPojo.getCompetitionid());//绑定比赛id
                    orders.setOrderType(stockPositionsUtils.setOrdersOrderType(creatOrderPojo.getOrderType()));
                    orders.setBuyMethod(orders.getOrderType().substring(2));
                    orders.setStockCode(creatOrderPojo.getStockCode());
                    orders.setStockName(creatOrderPojo.getStockName());
                    orders.setPrice(creatOrderPojo.getPrice());
                    orders.setOrderQuantity(creatOrderPojo.getQuantity());
                    orders.setTime(new Date());
                    // 如果为即时买入则说明订单已完成
                    if(creatOrderPojo.getOrderType().equals(1)){
                        orders.setFinishQuantity(creatOrderPojo.getQuantity());
                        orders.setDrawQuantity(0);
                        orders.setOrderStatus("已成交");
                    }
                    else {
                        orders.setFinishQuantity(0);
                        orders.setDrawQuantity(0);
                        orders.setOrderStatus("未成交");
                        // 添加订单信息
                        String orderMessage = orderUtils.createOrderMessageNew(orders, UNFILLED);
                        // 发送订单消息
                        kafkaSenderUtils.sendOrderMessage("market-order-submissions", orderMessage);
                        return R.success("委托操作成功");
                    }
                    int inInsert = orderMapper.insert(orders);
                    if (inInsert > 0 ) {
                        // 如果为即时买入则新建StockPositions表
                        boolean create = stockPositionsUtils.createStockPositionNew(creatOrderPojo, userId);
                        if(create){
                            return R.success("交易成功!");
                        }
                        return R.failed("交易失败!");
                        // 如果为限价买入无需在这里创建StockPositions表，
                        // 在flink中等待交易成功后才创建新的StockPositions表
                    }
                }
                log.info("第一次买入该股票，但是更新fundAccount表失败！");
                return R.failed("交易失败！");
            }
        }
        //卖出
        if(SELL.equals(orderType.substring(2))){
            //查询持仓信息
            StockPositions positions = stockPositionsUtils.getStockPositionsNew(
                    userId,
                    creatOrderPojo.getCompetitionid(),
                    creatOrderPojo.getStockCode()
                    );
            //如果有持仓则更新持仓表即可
            if(positions!= null){
                //可交易股数
                int unexecutedQuantity = positions.getAvailableQuantity();
                //如果可交易股数大于或等于交易股数
                if (unexecutedQuantity >= (creatOrderPojo.getQuantity())) {
                    // 计算这部分卖出的股票按该股最新市场价在原有股票所占的盈亏比例
                    BigDecimal proFitLoss = BigDecimal.valueOf(positions.getQuantity())
                            .multiply(creatOrderPojo.getLast())
                            .setScale(2, RoundingMode.HALF_UP);
                    proFitLoss = proFitLoss.multiply(
                            BigDecimal.valueOf(creatOrderPojo.getQuantity())
                                    .divide(BigDecimal.valueOf(positions.getQuantity()), 2, RoundingMode.HALF_UP)
                    );

                    //修改FundAccounts账户表
                    boolean updateFundAccounts = fundAccountUtils.updateFundAccountsAfterTransactionNew(
                            creatOrderPojo,
                            userId,
                            positions.getCostPrice(),
                            proFitLoss,
                            creatOrderPojo.getOrderType());
                    //修改持仓信息
                    boolean updateStockPositions = stockPositionsUtils.updateStockPositionsAfterTransactionNew(
                            creatOrderPojo,
                            userId,
                            creatOrderPojo.getOrderType());

                    if (updateFundAccounts && updateStockPositions) {
                        //生成订单
                        orders.setOrderId(creatOrderPojo.getCompetitionid());//绑定比赛id(这里的意思是通过比赛id来生成orderid)
                        orders.setUserId(userId);
                        orders.setCompetitionId(creatOrderPojo.getCompetitionid());//绑定比赛id
                        orders.setOrderType(stockPositionsUtils.setOrdersOrderType(creatOrderPojo.getOrderType()));
                        orders.setBuyMethod(orders.getOrderType().substring(2));
                        orders.setStockCode(creatOrderPojo.getStockCode());
                        orders.setStockName(creatOrderPojo.getStockName());
                        orders.setPrice(creatOrderPojo.getPrice());
                        orders.setOrderQuantity(creatOrderPojo.getQuantity());
                        orders.setTime(new Date());
                        // 如果为即时卖出则说明订单已完成
                        if(creatOrderPojo.getOrderType().equals(3)){
                            orders.setFinishQuantity(creatOrderPojo.getQuantity());
                            orders.setDrawQuantity(0);
                            orders.setOrderStatus("已成交");
                        }
                        else {
                            orders.setFinishQuantity(0);
                            orders.setDrawQuantity(0);
                            orders.setOrderStatus("未成交");
                            // 添加订单信息
                            String orderMessage = orderUtils.createOrderMessageNew(orders, UNFILLED);
                            // 发送订单消息
                            kafkaSenderUtils.sendOrderMessage("market-order-submissions", orderMessage);
                            return R.success("委托操作成功");
                        }
                        int outInsert = orderMapper.insert(orders);
                        if (outInsert > 0) {
                            return R.success("交易成功！");
                        }
                        return R.failed("交易失败！");
                    }

                    return R.failed("交易失败！");
                }
                return R.failed("交易失败！当前可交易股数小于卖出股数！");
            }
            //如果没有持仓则返回错误
            else{
                return R.failed("您没有此股票的持仓，无法卖出！");
            }
        }
        return R.failed("交易失败！");
    }

    @Override
    @Transactional
    public R<T> creatOrder(String token, CreatOrderPojo creatOrderPojo) {
        //获取当前用户的id
        String decrypt = decryptToken.decrypt(token);
        String userName = spiltUtils.getUserName(decrypt);
        Integer userId = userUtil.getUserId(userName);
        //判断是否实名
        boolean realNameAuthentication = userUtil.getRealNameAuthentication(userId);
        if (!realNameAuthentication) {
            return R.failed("你还未进行实名认证！");
        }
        Orders orders = new Orders();

        // 前置判断
        String stockCode = creatOrderPojo.getStockCode();
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        //测试代码，将时间改为2024-03-12 00:00:00
        String test = "2024-01-01 00:16:14";
//        LocalDateTime localDateTime = LocalDateTime.now();
        LocalDateTime localDateTime = LocalDateTime.parse(test,df);
        Stock stock = clickHouseMapper.getStockInfo(stockCode,localDateTime);
        if(stock == null){
            return R.failed("此时刻无该股票数据！");
        }

        //判断今天是否为交易日
        if (!stockUtilsNew.isTradingDay(localDateTime.format(df))) {
            return R.failed("今天不是交易日!");
        }

        //判断该股票是否已经停牌
        if(stock.getStopReason() == 1){
            return R.failed("该股票已停牌，无法交易！");
        }

        //判断是买入还是卖出,分四种情况,即时买入,即时卖出,限价买入,限价卖出
        //判断是否下过买入订单，并且查询买入数量(有多少股)
        if (SELL.equals(creatOrderPojo.getOrderStatus())) {
            //判断是否是限价单的卖出
            if (LIMIT_ORDER.equals(creatOrderPojo.getOrderType())) {
                //判断挂单价格是否等于市场价格
                if (stock.getLast().compareTo(creatOrderPojo.getPrice()) == 0) {
                    return R.failed("请选择与市场价不同的价格！");
                }
                //判断挂单价格是否超过当天这只股票的涨停价或者低于其跌停价,如果是的话需要重新挂单
                BigDecimal upPrice = stock.getMaxUp();
                BigDecimal downPrice = stock.getMaxDown();
                if (stock.getLast().compareTo(upPrice) > 0) {
                    return R.failed("您当前挂单价格超过当天股票的涨停价了哦!请重新挂单!");
                }
                if (stock.getLast().compareTo(downPrice) < 0) {
                    return R.failed("您当前挂单价格低于当天股票的跌停价了哦!请重新挂单!");
                }
                PutOrders putOrders = putOrderUtils.createAndSubmitOrder(creatOrderPojo.getCompetitionid()
                        , userId
                        , creatOrderPojo.getOrderStatus()
                        , creatOrderPojo.getStockCode()
                        , creatOrderPojo.getStockName()
                        , creatOrderPojo.getPrice()
                        , creatOrderPojo.getQuantity()
                        , creatOrderPojo.getMultiply());
                if (putOrders != null) {
                    // 添加订单信息
                    String orderMessage = orderUtils.createOrderMessage(putOrders, UNFILLED);
                    // 发送订单消息
                    kafkaSenderUtils.sendOrderMessage("market-order-submissions", orderMessage);
                    return R.success("限价卖出委托操作成功！");
                }

                return R.failed("限价卖出委托操作失败！");
            }

            //判断市价单成交价格与市场价格是否一致
            if (stock.getLast().compareTo(creatOrderPojo.getPrice()) != 0) {
                return R.failed("交易价格要与市场价格保持一致！");
            }

            //补充，今天这个用户是否购买过此股票与他能否再买无关
            //判断是否可以交易此股票，今天是否购买过此股票
            boolean canTradeStock = stockUtils.canTradeStock(creatOrderPojo.getCompetitionid()
                    , userId
                    , creatOrderPojo.getStockCode());
            if (canTradeStock) {
                return R.failed("您还不可以交易此股票！");
            }


            //查询持仓信息
            StockPositions positions = stockPositionsUtils.getStockPositions(creatOrderPojo.getCompetitionid()
                    , userId
                    , creatOrderPojo.getStockCode()
                    , creatOrderPojo.getMarket());
            //成本价
            BigDecimal costPrice = positions.getCostPrice();
            //可交易股数
            int unexecutedQuantity = positions.getAvailableQuantity();
            //如果可交易股数大于或等于交易股数
            if (unexecutedQuantity >= (creatOrderPojo.getQuantity() / creatOrderPojo.getMultiply())) {
                //修改账户
                boolean updateFundAccounts = fundAccountUtils.updateFundAccountsAfterTransaction(creatOrderPojo.getCompetitionid()
                        , userId
                        , creatOrderPojo.getPrice()
                        , creatOrderPojo.getQuantity()
                        , creatOrderPojo.getMultiply()
                        , costPrice);
                //修改持仓信息
                boolean updateStockPositions = stockPositionsUtils.updateStockPositionsAfterTransaction(creatOrderPojo.getCompetitionid()
                        , userId
                        , creatOrderPojo.getStockCode()
                        , creatOrderPojo.getMarket()
                        , creatOrderPojo.getQuantity()
                        , creatOrderPojo.getMultiply()
                        , creatOrderPojo.getPrice());

                if (updateFundAccounts && updateStockPositions) {
                    //生成订单
                    orders.setOrderId(creatOrderPojo.getCompetitionid());//绑定比赛id(这里的意思是通过比赛id来生成orderid)
                    orders.setUserId(userId);
                    orders.setCompetitionId(creatOrderPojo.getCompetitionid());//绑定比赛id
                    orders.setStockCode(creatOrderPojo.getStockCode());
                    orders.setStockName(creatOrderPojo.getStockName());
                    orders.setPrice(creatOrderPojo.getPrice());
                    orders.setOrderQuantity(creatOrderPojo.getQuantity() / creatOrderPojo.getMultiply());
                    orders.setFinishQuantity(0);
                    orders.setDrawQuantity(0);
                    orders.setOrderStatus(creatOrderPojo.getOrderStatus());
                    orders.setTime(new Date());
                    int outInsert = orderMapper.insert(orders);
                    if (outInsert > 0) {
                        return R.success("交易成功！");
                    }
                    return R.failed("交易失败！");
                }

                return R.failed("交易失败！");
            }
            return R.failed("交易失败！");
        }
        //判断是否是限价单的买入
        if (LIMIT_ORDER.equals(creatOrderPojo.getOrderStatus())) {
            //判断挂单价格是否等于市场价格
            if (creatOrderPojo.getLast().compareTo(creatOrderPojo.getPrice()) == 0) {
                return R.failed("请选则与市场价不同的价格！");
            }

            PutOrders putOrders = putOrderUtils.createAndSubmitOrder(creatOrderPojo.getCompetitionid()
                    , userId
                    , creatOrderPojo.getOrderStatus()
                    , creatOrderPojo.getStockCode()
                    , creatOrderPojo.getStockName()
                    , creatOrderPojo.getPrice()
                    , creatOrderPojo.getQuantity()
                    , creatOrderPojo.getMultiply());
            if (putOrders != null) {
                // 添加订单信息
                String orderMessage = orderUtils.createOrderMessage(putOrders, UNFILLED);
                // 发送订单消息
                kafkaSenderUtils.sendOrderMessage("market-order-submissions", orderMessage);
                return R.success("委托操作成功");
            }
            return R.failed("操作失败");
        }

        //判断市价单成交价格与市场价格是否一致
        if (MARKET_ORDER.equals(creatOrderPojo.getOrderType()) && creatOrderPojo.getLast().compareTo(creatOrderPojo.getPrice()) != 0) {
            return R.failed("交易价格要与市场价格保持一致！");
        }

        //判断用户是否购买过此股票
        StockPositions positions = stockPositionsUtils.getStockPositions(creatOrderPojo.getCompetitionid()
                , userId
                , creatOrderPojo.getStockCode()
                , creatOrderPojo.getMarket());

        if (positions != null) {
            boolean update = fundAccountUtils.updateFundAccountsForBuyTransaction(creatOrderPojo.getCompetitionid()
                    , userId
                    , creatOrderPojo.getPrice()
                    , creatOrderPojo.getQuantity()
                    , creatOrderPojo.getMultiply());
            if (update) {
                orders.setOrderId(creatOrderPojo.getCompetitionid());//绑定比赛id(这里的意思是通过比赛id来生成orderid)
                orders.setUserId(userId);
                orders.setCompetitionId(creatOrderPojo.getCompetitionid());//绑定比赛id
                orders.setStockCode(creatOrderPojo.getStockCode());
                orders.setStockName(creatOrderPojo.getStockName());
                orders.setPrice(creatOrderPojo.getPrice());
                orders.setOrderQuantity(creatOrderPojo.getQuantity() / creatOrderPojo.getMultiply());
                orders.setFinishQuantity(0);
                orders.setDrawQuantity(0);
                orders.setOrderStatus(creatOrderPojo.getOrderStatus());
                orders.setTime(new Date());
                int insert = orderMapper.insert(orders);
                if (insert > 0) {
                    //修改买入时持仓信息
                    boolean stockPositionsUpdate = stockPositionsUtils.updateStockPositionsAfterBuyTransaction(creatOrderPojo.getCompetitionid()
                            , userId
                            , creatOrderPojo.getStockCode()
                            , creatOrderPojo.getMarket()
                            , creatOrderPojo.getQuantity()
                            , creatOrderPojo.getMultiply()
                            , creatOrderPojo.getPrice());
                    //添加购买总金额
                    QueryWrapper<TotalAmount> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("user_id", userId).eq("competition_id", creatOrderPojo.getCompetitionid());

                    // 从数据库中查询出对应的记录
                    TotalAmount totalAmount = totalAmountMapper.selectOne(queryWrapper);

                    // 计算新的amount值
                    BigDecimal newAmount = BigDecimal.valueOf(creatOrderPojo.getQuantity())
                            .divide(BigDecimal.valueOf(creatOrderPojo.getMultiply()), 0, RoundingMode.HALF_UP)
                            .multiply(creatOrderPojo.getPrice())
                            .setScale(2, RoundingMode.HALF_UP);
                    totalAmount.setAmount(totalAmount.getAmount().add(newAmount));
                    // 更新记录
                    int updateResult = totalAmountMapper.update(totalAmount, queryWrapper);
                    if (stockPositionsUpdate && updateResult > 0) {
                        return R.success("交易成功！");
                    }
                    return R.success("交易失败！");
                }
                return R.failed("交易失败！");
            }
            return R.failed("交易失败！");
        }
        orders.setOrderId(creatOrderPojo.getCompetitionid());//绑定比赛id(这里的意思是通过比赛id来生成orderid)
        orders.setUserId(userId);
        orders.setCompetitionId(creatOrderPojo.getCompetitionid());//绑定比赛id
        orders.setStockCode(creatOrderPojo.getStockCode());
        orders.setStockName(creatOrderPojo.getStockName());
        orders.setPrice(creatOrderPojo.getPrice());
        orders.setOrderQuantity(creatOrderPojo.getQuantity() / creatOrderPojo.getMultiply());
        orders.setFinishQuantity(0);
        orders.setDrawQuantity(0);
        orders.setOrderStatus(creatOrderPojo.getOrderStatus());
        orders.setTime(new Date());
        int inInsert = orderMapper.insert(orders);
        //添加购买总金额
        UpdateWrapper<TotalAmount> queryWrapper = new UpdateWrapper<>();
        queryWrapper.eq("user_id", userId).eq("competition_id", creatOrderPojo.getCompetitionid());
        // 从数据库中查询出对应的记录
        TotalAmount totalAmount = totalAmountMapper.selectOne(queryWrapper);

        // 计算新的amount值
        BigDecimal newAmount = BigDecimal.valueOf(creatOrderPojo.getQuantity())
                .divide(BigDecimal.valueOf(creatOrderPojo.getMultiply()), 0, RoundingMode.HALF_UP)
                .multiply(creatOrderPojo.getPrice())
                .setScale(2, RoundingMode.HALF_UP);
        totalAmount.setAmount(totalAmount.getAmount().add(newAmount));
        // 更新记录
        int updateResult = totalAmountMapper.update(totalAmount, queryWrapper);
        if (inInsert > 0 && updateResult > 0) {
            //第一次购买时修改账户信息
            boolean update = fundAccountUtils.updateFundAccountsFirstBuyTransaction(creatOrderPojo.getCompetitionid()
                    , userId
                    , creatOrderPojo.getPrice()
                    , creatOrderPojo.getQuantity()
                    , creatOrderPojo.getMultiply());
            if (update) {
                boolean insert = stockPositionsUtils.createStockPosition(creatOrderPojo.getCompetitionid()
                        , userId
                        , creatOrderPojo.getStockName()
                        , creatOrderPojo.getMarket()
                        , creatOrderPojo.getStockCode()
                        , creatOrderPojo.getQuantity()
                        , creatOrderPojo.getMultiply()
                        , creatOrderPojo.getPrice());
                if (insert) {
                    return R.success("交易成功！");
                }
                return R.success("交易失败！");
            }
            return R.failed("交易失败！");
        }
        return R.failed("交易失败！");
    }

    @Override
    public R<List<PutOrders>> getPutOrderList(String token, Integer id) {
        //获取当前用户的id
        String decrypt = decryptToken.decrypt(token);
        String userName = spiltUtils.getUserName(decrypt);
        Integer userId = userUtil.getUserId(userName);
        //判断是否实名
        boolean realNameAuthentication = userUtil.getRealNameAuthentication(userId);
        if (!realNameAuthentication) {
            return R.failed("你还未进行实名认证！");
        }
        //查询所有挂单
        QueryWrapper<PutOrders> putOrdersQueryWrapper = new QueryWrapper<>();
        putOrdersQueryWrapper
                .eq("order_id", id)
                .eq("user_id", userId);
        List<PutOrders> putOrders = putOrderMapper.selectList(putOrdersQueryWrapper);
        return R.success(putOrders);
    }

    @Override
    public R<List<Orders>> getOrderList(String token, Integer competitionId,String orderStatus , String buyMethod) {
        //判断是否实名
        String decrypt = decryptToken.decrypt(token);
        String userName = spiltUtils.getUserName(decrypt);
        Integer userId = userUtil.getUserId(userName);

        boolean realNameAuthentication = userUtil.getRealNameAuthentication(userId);
        if (!realNameAuthentication) {
            return R.failed("你还未进行实名认证！");
        }

        //先判断比赛是否结束,若已结束则返回
        QueryWrapper<Competitions> competitionsQueryWrapper = new QueryWrapper<>();
        competitionsQueryWrapper.eq("competition_id",competitionId);
        Competitions competitions = competitionMapper.selectOne(competitionsQueryWrapper);
        if (competitions == null) {
            return R.failed("比赛不存在!");
        }
        // 获取比赛的截止日期
        Date deadline = competitions.getEndDate();
        // 获取当前日期
        Date now = new Date();
        // 判断比赛截止日期是否到期
        if (now.after(deadline)) {
            return R.failed("比赛已截止!");
        }

        // 通过用户id ,比赛id ,挂单状态来确定挂单表
        QueryWrapper<Orders> ordersQueryWrapper = new QueryWrapper<>();
        List<Orders> orders = null;
        // 如果orderStatus非空，则进行条件筛选
        if( orderStatus.isEmpty()){
           ordersQueryWrapper
                    .eq("user_id", userId)
                    .eq("competition_id",competitionId);
        }
        else {
            ordersQueryWrapper
                    .eq("user_id", userId)
                    .eq("competition_id", competitionId)
                    .eq("status", orderStatus);
        }
            orders = orderMapper.selectList(ordersQueryWrapper);

        // 如果购买方式不为空则进行筛选
        if ( buyMethod.isEmpty()) {
            if ( orders.size() == 0) {
                return R.failed("您的订单表为空!");
            }
            return R.success(orders);
        }
        orders = orders.stream().filter(order -> order.getBuyMethod().equals(buyMethod)).collect(Collectors.toList());
        // 如果发现没有订单则返回
        if ( orders.size() == 0) {
            return R.failed("您的订单表为空!");
        }

        return R.success(orders);
    }

    //token获取用户id ,competitionId 大赛id,orderId 订单Id ,withdrawNumber 撤单数量
    // status 订单状态(五种状态，分别为 未成交，已成交，已撤单，部分撤单，已过期),time撤销这个委托时的时间
    @Override
    @Transactional
    public R<T> withdrawOrder(String token, int orderId ,int competitionId, int withdrawNumber , String orderStatus) {
        //判断是否实名
        String decrypt = decryptToken.decrypt(token);
        String userName = spiltUtils.getUserName(decrypt);
        Integer userId = userUtil.getUserId(userName);

        boolean realNameAuthentication = userUtil.getRealNameAuthentication(userId);
        if (!realNameAuthentication) {
            log.info("未实名认证");
            return R.failed("你还未进行实名认证！");
        }

        //先判断比赛是否结束,若已结束则返回
        QueryWrapper<Competitions> competitionsQueryWrapper = new QueryWrapper<>();
        competitionsQueryWrapper.eq("competition_id",competitionId);
        Competitions competitions = competitionMapper.selectOne(competitionsQueryWrapper);
        if (competitions == null) {
            log.info("比赛不存在");
            return R.failed("比赛不存在！");
        }
        // 获取比赛的截止日期
        Date deadline = competitions.getEndDate();
        // 获取当前日期
        Date now = new Date();
        // 判断比赛截止日期是否到期
        if (now.after(deadline)) {
            log.info("比赛已截止");
            return R.failed("比赛已截止，无法参加！");
        }

        //判断撤单数量是否为空,为空返回
        if (withdrawNumber == 0) {
            log.info("撤单数量不能为0");
            return R.failed("撤单数量不能为0!");
        }

        // 判断挂单状态，如果为已成交,已撤单，已过期，则不能撤单
        if("已成交".equals(orderStatus)){
            log.info("您的订单已成交，无法撤单!");
            return R.failed("您的订单已成交，无法撤单!");
        }

        if("已撤单".equals(orderStatus)){
            log.info("您的订单已撤单，无法再次撤单!");
            return R.failed("您的订单已撤单，无法再次撤单!");
        }

        if("已过期".equals(orderStatus)){
            log.info("您的订单已过期，无法撤单!");
            return R.failed("您的订单已过期，无法撤单!");
        }

         // 通过用户id ,比赛id ,挂单状态来确定挂单表

        UpdateWrapper<Orders> ordersUpdateWrapper = new UpdateWrapper<>();
            ordersUpdateWrapper
                    .eq("user_id",userId)
                    .eq("competition_id",competitionId)
                    .eq("order_id", orderId);
        Orders orders = orderMapper.selectOne(ordersUpdateWrapper);

        // 如果发现没有订单则返回
        if ( orders == null) {
            log.info("您的订单表为空!");
            return R.failed("您的订单表为空!");
        }
        //判断撤单数量是否大于挂单数量,如果发现大于则返回错误
        if ( orders.getOrderQuantity() < withdrawNumber) {
            log.info("撤单数量超过当前挂单数量!");
            return R.failed("撤单数量超过当前挂单数量!");
        }

        //订单表中的剩余数量
        orders.setOrderQuantity(orders.getOrderQuantity() - withdrawNumber);
        // 更新撤单数量
        orders.setDrawQuantity(orders.getDrawQuantity() + withdrawNumber);
        orders.setOrderStatus("部分撤单");
        if(orders.getOrderQuantity() == 0){
            orders.setOrderStatus("已撤单");
        }

        int update = orderMapper.update(orders, ordersUpdateWrapper);
        if(update<0){
            log.info("订单表状态更新失败!");
            return R.failed("订单表状态更新失败!");
        }

        //再更新账户余额 FundAccounts 修改 总可用资金并更新总资产
        //计算这部分撤单的总资金,精确到小数点后两位
        // 查询平台账户信息,使用大赛id和用户id可唯一确定一张表
        UpdateWrapper<FundAccounts> fundAccountsQueryWrapper = new UpdateWrapper<>();
        fundAccountsQueryWrapper.eq("competition_id", competitionId)
                .eq("user_id", userId);
        FundAccounts fundAccounts = fundAccountMapper.selectOne(fundAccountsQueryWrapper);


        // 更新总可用资金
        fundAccounts.setAvailableFund(fundAccounts.getAvailableFund()
                .add(orders.getPrice().multiply(BigDecimal.valueOf(withdrawNumber)))
                .setScale(2, RoundingMode.HALF_UP));

        // 更新冻结资金
        fundAccounts.setFrozenFund(fundAccounts.getFrozenFund()
                .subtract(orders.getPrice().multiply(BigDecimal.valueOf(withdrawNumber)))
                .setScale(2, RoundingMode.HALF_UP));

        // 总资产无需更新

        int update1 = fundAccountMapper.update(fundAccounts, fundAccountsQueryWrapper);
        if(update1<0){
            log.info("用户资金账户表更新失败!");
            return R.failed("用户资金账户表更新失败!");
        }
        return R.success("撤单操作成功!");
    }


}

